package doc2db.fileWorker;

import doc2db.fileWorker.xml.TableParam;
import doc2db.fileWorker.xml.XMLParser;
import doc2db.fileWorker.xml.DbParam;
import doc2db.Keey;
import doc2db.fileWorker.xml.TreeParseHelper;
import doc2db.interfaces.TreeTabViewer;
import doc2db.table.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;


/**
 * <p><b>Класс обработчик документов</b></p>
 * @author yuriy
 */
public class ParseDocument {
    /**таблици*/
    private List<DocTable> tables = new ArrayList<DocTable>();
    /**имя документа*/
    private String fileName;
    /**обработчик таблиц*/
    public final RefactorTable refactorTable = new RefactorTable(tables);
    /*XMLParser**/
    private XMLParser xmlParser = new XMLParser();

    /**[2][*]название столбйа и инфо. часть (для всех строк одинаковая)*/
    private String tabHead [][];
    /**[2][*]название столбйа и инфо. часть (для всех строк одинаковая)*/
    private String tabInfo [][];

    /**параметры таблици*/
    private TableParam tableParam;
    /**параметры запросов к БД*/
    private DbParam dbParam;

    /**элючтратор обработонного документа*/
    private TreeTabViewer viewer = new TreeTabViewer();

    /**
     *  <p><b>Конструктор</b></p>
     * <p>Использование данного конструктора приведёт к неработоспособности
     * данного класса</p>
     */
    private ParseDocument() {
    }

    /**
     *  <p><b>Конструктор</b></p>
     * <p>Правельный конструктор</p>
     * @param fileName <p>имя файла для обработки (указывается полный путь)</p>
     */
    public ParseDocument(String fileName) {
        this.fileName = fileName;
    }

    /**
     *  <p><b>Главный метод, вызов которого необходим</b></p>
     *  <p>Разбирает документ (*.doc), находя внём таблицы и хранит из в
     * переменной класса DocTable</p>
     *  <p>Алгоритм заключается в том что мы поликсемно проходим по
     * документу, проверяя каждый "пораграф". Найдя первый "пораграф"
     * пренадлежащий таблице начинается формирование таблици.
     * Это происходит до тех пор пока не встретится первый "пораграф"
     * пренадлежащий не таблице. И так до конца документа</p>
     */
    public boolean parse() {
        HWPFDocument doc = null;
        doc = this.initHWFDocument();
        if(doc == null)
            return false;
        Range range = doc.getRange();

        int i = 0;
        boolean head = false;
        boolean body = false;
        DocTable docTable = null;

        boolean isHeadInit = false;//инициализированы ли верхние заголовки
        StringBuffer between = new StringBuffer();//иформация перед таблицей
        ParseHelperInterface ph;
        if(xmlParser.isIsTreeType())
            ph = new TreeParseHelper(new ParseHelper(), xmlParser.getTreeTypeNodes());
        else
            ph = new ParseHelper();
        boolean isBeeInTab = false;
        String [][] arr = null;

        Table __t = null;   //представление таблици в виде org.apache.poi.hwpf
        int rowiter = 0;    //какую строку обрабатываем
        int celliter = 0;   //какую ячейку в строке обрабатываем

        String t_text = "";
        //System.out.println(range.numParagraphs());
        while (i < range.numParagraphs()) {
            Paragraph p = null;
            try {
                try {
                    p = range.getParagraph(i);
                } catch (NullPointerException e) {
                    throw new ArrayIndexOutOfBoundsException();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                if (i > 0) {
                    System.err.println("can read paragraph after : \"" + range.getParagraph(i - 1).text() + "\"");
                }
                i++;
                continue;
            }
            
            if (p.isInTable()) {

                if (!head && !body) {
                    __t = range.getTable(p);
                    rowiter = celliter = 0;
                    
                    head = true;
                    body = true;
                    docTable = new DocTable();
                    tables.add(docTable);

                    if (!isHeadInit) {
                        System.err.println("xmlParser.isNullInHead=" + xmlParser.isNullInHead());
                        if (!xmlParser.isNullInHead()) {
                            tabHead = ph.getInfoInSuggestion(between, xmlParser.getHeadInfo(), false);
                        }
                        isHeadInit = true;
                    }
                    head = this.beforeIncludedTable(ph, between, docTable);
                    //Линейно/between = new StringBuffer("");
                    if(ph instanceof TreeParseHelper)
                        ((TreeParseHelper)ph).initListBeginValue(between);
                }

                if ((! isBeeInTab)) {
                    if (xmlParser.isIsTreeType()) {
                        if (ph instanceof TreeParseHelper) {
//                            System.out.println("Paragraph:" + between.toString());
                            if (Keey.debug)
                                ((TreeParseHelper) ph).print();//выводит список для обработки дополнений
                            arr = ((TreeParseHelper) ph).toComplementRow(docTable, between);
                            viewer.addText("</table>");
                            viewer.addText("\n\n\n");
                            viewer.addText("<p><i color=green>" + between.toString() + "</i></p>");
                            viewer.addText("<table border=1>");
                            for (int j = 0; j < arr.length; j++) {
                                viewer.addText("<tr>");
                                for (int k = 1; k < arr[j].length; k++) {
                                    viewer.addText("<th color=blue>" + " " + arr[j][k] + "</th>");
                                }
                                viewer.addText("</tr>");
                            }
                            viewer.addText("</table>");
                            viewer.addText("<table border=1>");
                        }
                    }
                }
                isBeeInTab = true;

                if (head && body) {
                    if (p.isTableRowEnd()) {
                        head = false;
                        if (tableParam.isNeedChangeHeadName() && !tableParam.isNeedMyHeadName()) {
                            tableParam.changeHeadName(docTable.getHead().get(), docTable.getHead());
                        }
                        this.toComplementTabHead(docTable, ph);
                    } else {
                        //String text = p.text().replace('\r', '\n');
                        //docTable.addHeadCell(text.substring(0, text.length() - 1));
                        String t = p.text();
                        if(t.charAt(t.length() -1) == 7){
                            String text = t.replace('\'', '`');
                            t_text += text.substring(0, text.length() - 1);
                            docTable.addHeadCell(t_text, __t.getRow(rowiter).getCell(celliter).getWidth());
                            t_text = "";
                            celliter++;
                            if(celliter >= __t.getRow(rowiter).numCells()){
                                celliter = 0;
                                rowiter ++;
                            }
                        }else{
                            String text = p.text().replace('\'', '`');
                            t_text += text.substring(0, text.length() - 1) + "\n";
                        }
                    }
                }

                else if (body) {
                    if (p.isTableRowEnd()) {
                        if (! xmlParser.isIsTreeType()) {
                            this.toComplementTabBodyRow(docTable);
                        } else {
                            if(arr != null){
                                viewer.addText("<tr>");
                                DocTableRows r = docTable.getBody().getCurrentRows();
                                for(int row = 0 ; row < r.size() ; row++){
                                    viewer.addText("<td>" + r.get(row) + "</td>");
                                }
                                for (int sj = 0; sj < arr[0].length; sj++) {
                                    if (arr[1][sj] == null ? "null" != null : !arr[1][sj].equals("null")) {
                                        try {
                                            viewer.addText("<td>" + new DocTableCell
                                                    (arr[1][sj], arr[0][sj]).toString() + "</td>");
                                            docTable.addBodyCell(arr[1][sj], arr[0][sj], 1);
                                        } catch (java.lang.NullPointerException e) {
                                        }
                                    }
                                }
                                viewer.addText("</tr>");
                            }else{
                                viewer.addText("<h3><i color=red>немогу ничего добавить</i></h3>\n");
                            }
                        }
                        docTable.addNewRow();
                    } else {
                        if(p.text().charAt(p.text().length() -1) == 7){
                            String text = p.text().replace('\'', '`');
                            t_text += text.substring(0, text.length() - 1);
                            docTable.addBodyCell(t_text, DocTable.NEXT, 
                                    __t.getRow(rowiter).getCell(celliter).getWidth() );
                            t_text = "";
                            celliter++;
                            if(celliter >= __t.getRow(rowiter).numCells()){
                                celliter = 0;
                                rowiter ++;
                            }
                        }else{
                            String text = p.text().replace('\'', '`');
                            t_text += text.substring(0, text.length() - 1) + "\n";
                        }
                    }
                }
            }

            else {
                if (isBeeInTab) {
                    between = new StringBuffer("");
                    dbParam.setTableHeadType(docTable.getHead());
                    isBeeInTab = false;
                }
                String s = "" + p.text().replaceAll("\r", "LINE_END").replace('\'', '`');
                between.append(s);// + "LINE_END");
                head = false;
                body = false;
            }
            i++;
        }
        if (!Keey.isIsMas()) {
            if (Keey.viewTree) {
                viewer.showMe();
            }
        }
        //System.out.println("\n\n\n"+i+":"+range.numParagraphs()+range.getParagraph(i-1).text()+"\n\n\n");
        return true;
    }

    /**
     * <p>Перед чтением таблици</p>
     */
    private boolean beforeIncludedTable(ParseHelperInterface ph, StringBuffer between, DocTable docTable) {
        boolean head = true;
        if (!xmlParser.isNullInInfo()) {
            tabInfo = ph.getInfoInSuggestion(between, xmlParser.getInfoInfo(), false);
        }
        if (tableParam.isNeedMyHeadName()) {
            for (int j = 0; j < tableParam.getMyHeadName().length; j++) {
                docTable.addHeadCell(tableParam.getMyHeadName()[j], 0);
            }
            head = false;
            this.toComplementTabHead(docTable, ph);
        }
        return head;
    }

    /**
     * <p>дополнить заголовки таблици</p>
     */
    private void toComplementTabHead(DocTable docTable, ParseHelperInterface ph) {
        if (!xmlParser.isNullInHead()) {
            ph.addHeadCellFromDocHead(docTable, tabHead);
        }
        if (!xmlParser.isNullInInfo()) {
            ph.addHeadCellFromDocHead(docTable, tabInfo);
        }
    }

    /**
     * <p>дополнить колонками текущюю стоку</p>
     */
    private void toComplementTabBodyRow(DocTable docTable) {
        if (!xmlParser.isNullInHead()) {
            for (int j = 0; j < tabHead[1].length; j++) {
                String s = "" + tabHead[1][j];
                if (!s.equals("null")) {
                    docTable.addBodyCell(tabHead[1][j], tabHead[0][j], 1);
                }
            }
        }
        if (!xmlParser.isNullInInfo()) {
            for (int j = 0; j < tabInfo[1].length; j++) {//tabInfo[0].
                String s = "" + tabInfo[1][j];
                if (!s.equals("null")) {
                    docTable.addBodyCell(tabInfo[1][j], tabInfo[0][j], 1);
                }
            }
        }
    }

    /**
     * <p>init parsing document</p>
     * @return <p>document</p>
     */
    private HWPFDocument initHWFDocument() {
        HWPFDocument doc = null;
        try {
            POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(fileName));
            doc = new HWPFDocument(fs);
        } catch (FileNotFoundException e1) {
            if (Keey.debug) {
                e1.printStackTrace();
            }
            System.err.println("Fatal eror : " + e1);
            return null;
        } catch (IOException e1) {
            if (Keey.debug) {
                e1.printStackTrace();
            }
            System.err.println("Fatal eror : " + e1);
            return null;
        }
        try {
            xmlParser.initTagsName();
            xmlParser.insertInfo();
            tableParam = xmlParser.getTableParam();
            dbParam = xmlParser.getDbParam();
        } catch (ParserConfigurationException ex) {
            System.err.println(ex);
        } catch (SAXException ex) {
            System.err.println(ex);
        } catch (IOException ex) {
            System.err.println(ex);
        }

        return doc;
    }

    /**
     *  <p>Получения талици для занесения в БД.
     * Метод имеет смысл, только после вызова метода <i>refactor</i> или
     * полсе метода <i>refactorCreateReturnTables</i></p>
     * @return
     */
    public List<DocTable> getTables() {
        return tables;//returnTables;
    }

    /**
     *  <p>Получить размер таблици</p>
     * @return <p>размер таблици</p>
     */
    public int size() {
        return tables.size();
    }

    /**
     *  <p>Преоброзавание таблици к необходимому формату</p>
     * @return  <p>Класс с методами преобразования</p>
     */
    public RefactorTable refactor() {
        return refactorTable;
    }
}

